package org.onvivals.app.ai.asr;

import com.alibaba.nls.client.AccessToken;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class NlpServiceImpl implements NlpService {

	@Value("${aliyun.nls.appKey}")
	private String appKey;
	@Value("${aliyun.nls.accessKeyId}")
	private String accessKeyId;
	@Value("${aliyun.nls.accessKeySecret}")
	private String accessKeySecret;

	@Autowired
	RedisTemplate<String, String> redisTemplate;

	public static Map<String, SpeechTranslationService> stringSpeechTranslationServiceConcurrentHashMap = new ConcurrentHashMap<>();

	@Override
	public void speechTranslation(byte[] byteArray, String channel) {
		try {
			SpeechTranslationService speechTranslationService = stringSpeechTranslationServiceConcurrentHashMap.get(channel);
			if (speechTranslationService == null) {
				init(channel);
				speechTranslationService = stringSpeechTranslationServiceConcurrentHashMap.get(channel);
			}
			speechTranslationService.process(channel, byteArray);
		} catch (Exception e) {
			log.error("语音转换失败: {}", channel, e);
			// 出错时直接创建新的实例
			try {
				close(channel);
				init(channel);
			} catch (Exception ex) {
				log.error("创建新实例失败: {}", channel, ex);
			}
		}
	}

	@Override
	public void init(String channel) {
		try {
			String key = "nlp:token";
			String token;
			Long ttl = redisTemplate.getExpire(key, TimeUnit.MILLISECONDS);

			// Token 过期或不存在时重新获取
			if (ttl == null || ttl < 0) {
				NlsClientService.applyAccessToken(accessKeyId, accessKeySecret);
				AccessToken accessToken = NlsClientService.getAccessToken();
				token = accessToken.getToken();
				redisTemplate.opsForValue().set(key, token, 6, TimeUnit.HOURS);
				NlsClientService.getNlsClient().setToken(token);
			} else {
				token = redisTemplate.opsForValue().get(key);
				if (token == null) {
					NlsClientService.applyAccessToken(accessKeyId, accessKeySecret);
					AccessToken accessToken = NlsClientService.getAccessToken();
					token = accessToken.getToken();
					redisTemplate.opsForValue().set(key, token, 6, TimeUnit.HOURS);
					NlsClientService.getNlsClient().setToken(token);
				}
			}

			// 移除旧的服务实例
			SpeechTranslationService oldService = stringSpeechTranslationServiceConcurrentHashMap.remove(channel);
			if (oldService != null) {
				try {
					oldService.close(channel);
				} catch (Exception e) {
					log.warn("关闭旧服务实例失败: {}", channel, e);
				}
			}

			// 创建新的服务实例
			SpeechTranslationService service = new SpeechTranslationService(appKey, token, channel);
			stringSpeechTranslationServiceConcurrentHashMap.put(channel, service);
			log.info("成功初始化语音服务: {}", channel);
		} catch (Exception e) {
			log.error("初始化语音服务失败: {}", channel, e);
			throw new RuntimeException("初始化语音服务失败: " + channel, e);
		}
	}

	@Override
	public String text(String deviceNum) {
		try {
			SpeechTranslationService speechTranslationService = stringSpeechTranslationServiceConcurrentHashMap.get(deviceNum);
			if (speechTranslationService != null) {
				try {
					return speechTranslationService.text(deviceNum);
				} catch (Exception e) {
					log.error("获取文本失败，创建新实例: {}", deviceNum, e);
					// 出错时创建新实例
					close(deviceNum);
					init(deviceNum);
					speechTranslationService = stringSpeechTranslationServiceConcurrentHashMap.get(deviceNum);
					return speechTranslationService.text(deviceNum);
				}
			}
		} catch (Exception e) {
			log.error("获取文本最终失败: {}", deviceNum, e);
		}
		return "";
	}

	@Override
	public void close(String channel) {
		try {
			SpeechTranslationService speechTranslationService = stringSpeechTranslationServiceConcurrentHashMap.remove(channel);
			if (speechTranslationService != null) {
				speechTranslationService.close(channel);
				log.info("关闭channel成功: {}", channel);
			}
		} catch (Exception e) {
			log.error("关闭channel失败: {}", channel, e);
		}
	}
}
